package de.mmis.core.publishsubscribe;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import de.mmis.core.base.DeserializableAnnotations.DeserializationMethod;
import de.mmis.core.base.abstracttree.InnerNode;
import de.mmis.core.base.abstracttree.Tree;
import de.mmis.core.base.abstracttree.serializer.DeserializableException;
import de.mmis.core.base.abstracttree.serializer.Serializable;
import de.mmis.core.base.event.Event;
import de.mmis.core.base.gclass.GClass;
import de.mmis.core.base.gclass.GParameterized;

/**
 * internal class, being public only for deserialization.<br/>
 * This class stores an {@link Event} in a class-indepentand way.
 * 
 * @author Martin Nyolt
 * 
 */
public class PlainEvent implements Serializable, Event {

	String originalClass;
	Set<String> classes;
	Map<String, Tree> eventData;
	Tree serializedEvent;

	public PlainEvent(String originalClass, Set<String> classes,
			Map<String, Tree> eventData, Tree serializedEvent) {
		this.originalClass = originalClass;
		this.classes = classes;
		this.eventData = eventData;
		this.serializedEvent = serializedEvent;
	}

	public Map<String, Tree> getEventData() {
		return eventData;
	}

	@Override
	public Tree[] serialize(boolean explicit, Map<Object, String> refmap,
			ClassLoader classLoader) {
		Tree[] result = new Tree[4];

		result[0] = Tree.fromObject(originalClass, explicit, refmap,
				classLoader);

		InnerNode classes_s = new InnerNode();
		for (String s : classes)
			classes_s.add(Tree.fromObject(s, explicit, refmap, classLoader));

		result[1] = classes_s;
		result[2] = Tree.fromObject(eventData, explicit, refmap, classLoader);
		result[3] = Tree.fromObject(serializedEvent, explicit, refmap,
				classLoader);

		return result;
	}

	@Override
	public String getTypeIdentifier() {
		return "publishsubscribe/plain-event";
	}

	@DeserializationMethod
	public static PlainEvent deserialize(Tree[] exps, ClassLoader cl,
			String id, Map<String, Object> idmap)
			throws DeserializableException {
		if (exps.length != 4)
			throw new DeserializableException(null,
					"Accept only four parameters");

		Tree originalClass_e = exps[0];
		String originalClass = originalClass_e.getAsString();

		Tree classes_ = exps[1];
		if (!(classes_ instanceof InnerNode))
			throw new DeserializableException(classes_,
					"expected a struct with classes, but did not found a struct");
		InnerNode classes_s = (InnerNode) classes_;

		Set<String> classes = new HashSet<String>();
		for (Tree s : classes_s)
			try {
				classes.add(s.getAsString());
			} catch (DeserializableException de) {
				throw new DeserializableException(s, de,
						"Class must be a String");
			}

		GParameterized clazz = new GParameterized(Map.class, new GClass[] {
				GClass.fromClass(String.class), GClass.fromClass(Tree.class) });

		Map<String, Tree> eventData = exps[2].getAs(clazz);
		Tree serializedEvent = exps[3].getAs(Tree.class);

		return new PlainEvent(originalClass, classes, eventData,
				serializedEvent);
	}

	@Override
	public String toString() {
		return Tree.fromObject(this, false).toString();
	}
}
